home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint108s.zoo / filesys.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-02  |  31.3 KB  |  1,259 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993 Atari Corp.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * various file system interface things
  9.  */
  10.  
  11. #include "mint.h"
  12.  
  13. #define PATH2COOKIE_DB(x) TRACE(x)
  14.  
  15. FILESYS *active_fs;
  16. FILESYS *drives[NUM_DRIVES];
  17. extern FILESYS tos_filesys;    /* declaration needed for debugging only */
  18.  
  19. /* "aliased" drives are different names
  20.  * for real drives/directories
  21.  * if drive d is an alias for c:\usr,
  22.  * then alias_drv[3] == 2 (the real
  23.  * drive) and aliases has bit (1L << 3)
  24.  * set.
  25.  * NOTE: if aliasdrv[d] is 0, then d is not an aliased drive,
  26.  * otherwise d is aliased to drive aliasdrv[d]-1
  27.  * (e.g. if drive A: is aliased to B:\FOO, then
  28.  * aliasdrv[0] == 'B'-'A'+1 == 2). Always remember to
  29.  * compensate for the extra 1 when dereferencing aliasdrv!
  30.  */
  31. int    aliasdrv[NUM_DRIVES];
  32.  
  33. FILEPTR *flist;        /* a list of free file pointers */
  34.  
  35. char follow_links[1];    /* dummy "name" used as a parameter to path2cookie */
  36.  
  37. /* vector of valid drives, according to GEMDOS */
  38. /* note that this isn't necessarily the same as what the BIOS thinks of
  39.  * as valid
  40.  */
  41. long dosdrvs;
  42.  
  43. /*
  44.  * Initialize a specific drive. This is called whenever a new drive
  45.  * is accessed, or when media change occurs on an old drive.
  46.  * Assumption: at this point, active_fs is a valid pointer
  47.  * to a list of file systems.
  48.  */
  49.  
  50. /* table of processes holding locks on drives */
  51. extern PROC *dlockproc[];    /* in dosdir.c */
  52.  
  53. void
  54. init_drive(i)
  55.     int i;
  56. {
  57.     long r;
  58.     FILESYS *fs;
  59.     fcookie root_dir;
  60.  
  61.     TRACE(("init_drive(%c)", i+'A'));
  62.  
  63.     drives[i] = 0;        /* no file system */
  64.     if (i >= 0 && i < NUM_DRIVES) {
  65.         if (dlockproc[i]) return;
  66.     }
  67.  
  68.     for (fs = active_fs; fs; fs = fs->next) {
  69.         r = (*fs->root)(i, &root_dir);
  70.         if (r == 0) {
  71.             drives[i] = root_dir.fs;
  72.             release_cookie(&root_dir);
  73.             break;
  74.         }
  75.     }
  76. }
  77.  
  78. /*
  79.  * initialize the file system
  80.  */
  81.  
  82. #define NUMFPS    40    /* initial number of file pointers */
  83.  
  84. void
  85. init_filesys()
  86. {
  87.     static FILEPTR initial[NUMFPS+1];
  88.     int i;
  89.     extern FILESYS tos_filesys, bios_filesys, pipe_filesys,
  90.         proc_filesys, uni_filesys;
  91.  
  92. /* get the vector of connected GEMDOS drives */
  93.     dosdrvs = Dsetdrv(Dgetdrv()) | drvmap();
  94.  
  95. /* set up some initial file pointers */
  96.     for (i = 0; i < NUMFPS; i++) {
  97.         initial[i].devinfo = (ulong) (&initial[i+1]);
  98.     }
  99.     initial[NUMFPS].devinfo = 0;
  100.     flist = initial;
  101.  
  102. /* set up the file systems */
  103.     tos_filesys.next = 0;
  104.     bios_filesys.next = &tos_filesys;
  105.     pipe_filesys.next = &bios_filesys;
  106.     proc_filesys.next = &pipe_filesys;
  107.     uni_filesys.next = &proc_filesys;
  108.  
  109.     active_fs = &uni_filesys;
  110.  
  111. /* initialize the BIOS file system */
  112.     biosfs_init();
  113.  
  114. /* initialize the unified file system */
  115.     unifs_init();
  116. }
  117.  
  118. /*
  119.  * load file systems from disk
  120.  * this routine is called after process 0 is set up, but before any user
  121.  * processes are run
  122.  *
  123.  * NOTE that a number of directory changes take place here: we look first
  124.  * in the current directory, then in the directory \mint.
  125.  */
  126.  
  127. typedef FILESYS * ARGS_ON_STACK (*FSFUNC) P_((struct kerinfo *));
  128.  
  129. /* uk: made this lie outside of functions, as load_filesys() and
  130.  *     load_devdriver() need access to it.
  131.  */
  132. #define NPATHS 3
  133. static const char *ext_paths[NPATHS] = {"", "\\MINT", "\\MULTITOS"};
  134.  
  135.  
  136. void
  137. load_filesys()
  138. {
  139.     long r;
  140.     BASEPAGE *b;
  141.     FILESYS *fs;
  142.     FSFUNC initf;
  143.     static DTABUF dta;
  144.     int i;
  145.     extern struct kerinfo kernelinfo; /* in main.c */
  146.     char curpath[PATH_MAX];
  147.     MEMREGION *xfsreg;
  148.  
  149.     curproc->dta = &dta;
  150.     d_getpath(curpath,0);
  151.  
  152.     for (i = 0; i < NPATHS; i++) {
  153.         if (*ext_paths[i]) {
  154. /* don't bother checking the current directory twice! */
  155.             if (!stricmp(ext_paths[i],curpath))
  156.             r = -1;
  157.             else
  158.             r = d_setpath(ext_paths[i]);
  159.         }
  160.         else
  161.             r = 0;
  162.  
  163.         if (r == 0)
  164.             r = f_sfirst("*.xfs", 0);
  165.  
  166.         while (r == 0) {
  167.         b = (BASEPAGE *)p_exec(3, dta.dta_name, (char *)"", (char *)0);
  168.         if ( ((long)b) < 0 ) {
  169.             DEBUG(("Error loading file system %s", dta.dta_name));
  170.             r = f_snext();
  171.             continue;
  172.         }
  173.     /* we leave a little bit of slop at the end of the loaded stuff */
  174.         m_shrink(0, (virtaddr)b, 512 + b->p_tlen + b->p_dlen + b->p_blen);
  175.         initf = (FSFUNC)b->p_tbase;
  176.         TRACE(("initializing %s", dta.dta_name));
  177.         fs = (*initf)(&kernelinfo);
  178.  
  179.         if (fs) {
  180.             TRACE(("%s loaded OK", dta.dta_name));
  181.     /* put the loaded XFS into super accesible memory */
  182.             xfsreg = addr2region( (long) b );
  183.             mark_region(xfsreg, PROT_S);
  184.  
  185.     /* link it into the list of drivers */
  186.     /* uk: but only if it has not installed itself via Dcntl()
  187.      *     after checking if file system is already installed,
  188.      *     so we know for sure that each file system in at most
  189.      *     once in the chain (important for removal!)
  190.      * also note: this doesn't preclude loading two different
  191.      * instances of the same file system driver, e.g. it's perfectly
  192.      * OK to have a "cdromy1.xfs" and "cdromz2.xfs"; the check below
  193.      * just makes sure that a given instance of a file system is
  194.      * installed at most once. I.e., it prevents cdromy1.xfs from being
  195.      * installed twice.
  196.      */
  197.             if ((FILESYS*)1L != fs) {
  198.                 FILESYS *f = active_fs;
  199.                 for (;  f;  f = f->next)
  200.                     if (f == fs)
  201.                         break;
  202.                 if (!f) {   /* we ran completly through the list */
  203.                     fs->next = active_fs;
  204.                     active_fs = fs;
  205.                 }
  206.             }
  207.         } else {
  208.             DEBUG(("%s returned null", dta.dta_name));
  209.             m_free((virtaddr)b);
  210.         }
  211.         r = f_snext();
  212.         }
  213.     }
  214.  
  215. #if 0
  216. /* here, we invalidate all old drives EXCEPT for ones we're already using (at
  217.  * this point, only the bios devices should be open)
  218.  * this gives newly loaded file systems a chance to replace the
  219.  * default tosfs.c
  220.  */
  221.     for (i = 0; i < NUM_DRIVES; i++) {
  222.         if (d_lock(1, i) == 0)    /* lock if possible */
  223.             d_lock(0, i);    /* and then unlock */
  224.     }
  225. #endif
  226. }
  227.  
  228.  
  229. /*
  230.  * uk: load device driver in files called *.xdd (external device driver)
  231.  *     from disk
  232.  * maybe this should go into biosfs.c ??
  233.  *
  234.  * this routine is called after process 0 is set up, but before any user
  235.  * processes are run, but before the loadable file systems come in,
  236.  * so they can make use of external device drivers
  237.  *
  238.  * NOTE that a number of directory changes take place here: we look first
  239.  * in the current directory, then in the directory \mint, and finally
  240.  * the d_lock() calls force us into the root directory.
  241.  * ??? what d_lock() calls ???
  242.  */
  243.  
  244. typedef DEVDRV * ARGS_ON_STACK (*DEVFUNC) P_((struct kerinfo *));
  245.  
  246. #define DEV_SELFINST  ((DEVDRV*)1L)  /* dev driver did dcntl() already */
  247.  
  248. void
  249. load_devdriver()
  250. {
  251.     long r;
  252.     BASEPAGE *b;
  253.     DEVDRV *dev;
  254.     DEVFUNC initf;
  255.     struct dev_descr the_dev;
  256.     static DTABUF dta;
  257.     int i;
  258.     extern struct kerinfo kernelinfo; /* in main.c */
  259.     char curpath[PATH_MAX];
  260.     char dev_name[PATH_MAX];  /* a bit long, but one never knows... */
  261.     char ch, *p;
  262.     MEMREGION *xddreg;
  263.  
  264.  
  265.     curproc->dta = &dta;
  266.     d_getpath(curpath,0);
  267.  
  268.     for (i = 0; i < NPATHS; i++) {
  269.         if (*ext_paths[i]) {
  270. /* don't bother checking the current directory twice! */
  271.             if (!stricmp(ext_paths[i],curpath))
  272.             r = -1;
  273.             else
  274.             r = d_setpath(ext_paths[i]);
  275.         }
  276.         else
  277.             r = 0;
  278.  
  279.         if (r == 0)
  280.             r = f_sfirst("*.xdd", 0);
  281.  
  282.         while (r == 0) {
  283.         b = (BASEPAGE *)p_exec(3, dta.dta_name, (char *)"", (char *)0);
  284.         if ( ((long)b) < 0 ) {
  285.             DEBUG(("Error loading device driver %s", dta.dta_name));
  286.             r = f_snext();
  287.             continue;
  288.         }
  289.     /* we leave a little bit of slop at the end of the loaded stuff */
  290.         m_shrink(0, (virtaddr)b, 512 + b->p_tlen + b->p_dlen + b->p_blen);
  291.         initf = (DEVFUNC)b->p_tbase;
  292.         TRACE(("initializing %s", dta.dta_name));
  293.         dev = (*initf)(&kernelinfo);
  294.  
  295.         if (dev) {
  296.             if (DEV_SELFINST != dev) {
  297.     /* we need to install the device driver ourselves */
  298.                 the_dev.driver = dev;
  299.                 the_dev.dinfo = 0;
  300.                 the_dev.flags = 0;
  301.                 the_dev.tty = (struct tty*)0L;
  302.                 the_dev.reserved[0] = the_dev.reserved[1] = 0;
  303.                 the_dev.reserved[2] = the_dev.reserved[3] = 0;
  304.                 p = dta.dta_name;
  305.                 while (*p && *p != '.') p++;
  306.                 ch = *p;
  307.                 *p = '\0';  /* we dont want the extension */
  308.                 strcpy(dev_name, "u:\\dev\\");
  309.                 strcat(dev_name, dta.dta_name);
  310.                 *p = ch;
  311.                 r = d_cntl(DEV_INSTALL, dev_name, (long)&the_dev);
  312.                 if (r <= 0) {
  313.                     DEBUG(("Error installing device driver %s", dta.dta_name));
  314.                     r = f_snext();
  315.                     continue;
  316.                 }
  317.             }
  318.             TRACE(("%s loaded OK", dta.dta_name));
  319.     /* put the loaded XDD into super accesible memory */
  320.             xddreg = addr2region( (long) b );
  321.             mark_region(xddreg, PROT_S);
  322.         } else {
  323.             DEBUG(("%s returned null", dta.dta_name));
  324.             m_free((virtaddr)b);
  325.         }
  326.         r = f_snext();
  327.         }
  328.     }
  329. }
  330.  
  331.  
  332. void
  333. close_filesys()
  334. {
  335.     PROC *p;
  336.     FILEPTR *f;
  337.     int i;
  338.  
  339.     TRACE(("close_filesys"));
  340. /* close every open file */
  341.     for (p = proclist; p; p = p->gl_next) {
  342.         for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  343.             if ( (f = p->handle[i]) != 0) {
  344.                 if (p->wait_q == TSR_Q || p->wait_q == ZOMBIE_Q)
  345.                     ALERT("Open file for dead process?");
  346.                 do_pclose(p, f);
  347.             }
  348.         }
  349.     }
  350. }
  351.  
  352. /*
  353.  * "media change" routine: called when a media change is detected on device
  354.  * d, which may or may not be a BIOS device. All handles associated with
  355.  * the device are closed, and all directories invalidated. This routine
  356.  * does all the dirty work, and is called automatically when
  357.  * disk_changed detects a media change.
  358.  */
  359.  
  360. void ARGS_ON_STACK 
  361. changedrv(d)
  362.     unsigned d;
  363. {
  364.     PROC *p;
  365.     int i;
  366.     FILEPTR *f;
  367.     FILESYS *fs;
  368.     SHTEXT *stext;
  369.     extern SHTEXT *text_reg;    /* in mem.c */
  370.     DIR *dirh;
  371.     fcookie dir;
  372.     int warned = (d & 0xf000) == PROC_BASE_DEV;
  373.     long r;
  374.  
  375. /* if an aliased drive, change the *real* device */
  376.     if (d < NUM_DRIVES && aliasdrv[d]) {
  377.         d = aliasdrv[d] - 1;    /* see NOTE above */
  378.     }
  379.  
  380. /* re-initialize the device, if it was a BIOS device */
  381.     if (d < NUM_DRIVES) {
  382.         fs = drives[d];
  383.         if (fs) {
  384.             (void)(*fs->dskchng)(d);
  385.         }
  386.         init_drive(d);
  387.     }
  388.  
  389.     for (p = proclist; p; p = p->gl_next) {
  390.     /* invalidate all open files on this device */
  391.         for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  392.             if (((f = p->handle[i]) != 0) && (f->fc.dev == d)) {
  393.                 if (!warned) {
  394.                 ALERT(
  395. "Files were open on a changed drive (0x%x)!", d);
  396.                 warned++;
  397.                 }
  398.  
  399. /* we set f->dev to NULL to indicate to do_pclose that this is an
  400.  * emergency close, and that it shouldn't try to make any
  401.  * calls to the device driver since the file has gone away
  402.  */
  403.                 f->dev = NULL;
  404.                 (void)do_pclose(p, f);
  405. /* we could just zero the handle, but this could lead to confusion if
  406.  * a process doesn't realize that there's been a media change, Fopens
  407.  * a new file, and gets the same handle back. So, we force the
  408.  * handle to point to /dev/null.
  409.  */
  410.                 p->handle[i] =
  411.                 do_open("U:\\DEV\\NULL", O_RDWR, 0, (XATTR *)0);
  412.             }
  413.         }
  414.  
  415.     /* terminate any active directory searches on the drive */
  416.         for (i = 0; i < NUM_SEARCH; i++) {
  417.             dirh = &p->srchdir[i];
  418.             if (p->srchdta[i] && dirh->fc.fs && dirh->fc.dev == d) {
  419.                 TRACE(("closing search for process %d", p->pid));
  420.                 release_cookie(&dirh->fc);
  421.                 dirh->fc.fs = 0;
  422.                 p->srchdta[i] = 0;
  423.             }
  424.         }
  425.  
  426.         for (dirh = p->searches; dirh; dirh = dirh->next) {
  427.             /* If this search is on the changed drive, release
  428.                the cookie, but do *not* free it, since the
  429.                user could later call closedir on it. */
  430.             if (dirh->fc.fs && dirh->fc.dev == d) {
  431.                 release_cookie (&dirh->fc);
  432.                 dirh->fc.fs = 0;
  433.             }
  434.         }
  435.             
  436.         if (d >= NUM_DRIVES) continue;
  437.  
  438.     /* change any active directories on the device to the (new) root */
  439.         fs = drives[d];
  440.         if (fs) {
  441.             r = (*fs->root)(d, &dir);
  442.             if (r != E_OK) dir.fs = 0;
  443.         } else {
  444.             dir.fs = 0; dir.dev = d;
  445.         }
  446.  
  447.         for (i = 0; i < NUM_DRIVES; i++) {
  448.             if (p->root[i].dev == d) {
  449.                 release_cookie(&p->root[i]);
  450.                 dup_cookie(&p->root[i], &dir);
  451.             }
  452.             if (p->curdir[i].dev == d) {
  453.                 release_cookie(&p->curdir[i]);
  454.                 dup_cookie(&p->curdir[i], &dir);
  455.             }
  456.         }
  457.         release_cookie(&dir);
  458.     }
  459.  
  460. /* free any file descriptors associated with shared text regions */
  461.     for (stext = text_reg; stext; stext = stext->next) {
  462.         f = stext->f;
  463.         if (f->fc.dev == d) {
  464.             f->dev = NULL;
  465.             do_pclose(rootproc, f);
  466.             stext->f = 0;
  467.         }
  468.     }
  469. }
  470.  
  471. /*
  472.  * check for media change: if the drive has changed, call changedrv to
  473.  * invalidate any open files and file handles associated with it, and
  474.  * call the file system's media change routine.
  475.  * returns: 0 if no change, 1 if change, negative number for error
  476.  */
  477.  
  478. int
  479. disk_changed(d)
  480.     int d;
  481. {
  482.     short r;
  483.     FILESYS *fs;
  484.     static char tmpbuf[8192];
  485.  
  486. /* for now, only check BIOS devices */
  487.     if (d < 0 || d >= NUM_DRIVES)
  488.         return 0;
  489. /* watch out for aliased drives */
  490.     if (aliasdrv[d]) {
  491.         d = aliasdrv[d] - 1;
  492.         if (d < 0 || d >= NUM_DRIVES)
  493.             return 0;
  494.     }
  495.  
  496. /* has the drive been initialized yet? If not, then initialize it and return
  497.  * "no change"
  498.  */
  499.     fs = drives[d];
  500.     if (!fs) {
  501.         TRACE(("drive %c not yet initialized", d+'A'));
  502.         changedrv(d);
  503.         return 0;
  504.     }
  505.  
  506. /* We have to do this stuff no matter what, because someone may have installed
  507.  * vectors to force a media change...
  508.  * PROBLEM: AHDI may get upset if the drive isn't valid.
  509.  * SOLUTION: don't change the default PSEUDODRIVES setting!
  510.  */
  511.  
  512. TRACE(("calling mediach(%d)",d));
  513.     r = (int)mediach(d);
  514. TRACE(("mediach(%d) == %d", d, r));
  515.  
  516.     if (r < 0) return r;
  517.     if (r == 1) {        /* drive _may_ have changed */
  518.         r = rwabs(0, tmpbuf, 1, 0, d, 0L);    /* check the BIOS */
  519.         if (r != E_CHNG) {            /* nope, no change */
  520.             TRACE(("rwabs returned %d", r));
  521.             return (r < 0) ? r : 0;
  522.         }
  523.         r = 2;            /* drive was definitely changed */
  524.     }
  525.     if (r == 2) {
  526.         TRACE(("definite media change"));
  527.         fs = drives[d];        /* get filesystem associated with drive */
  528.         if ((*fs->dskchng)(d)) { /* does the fs agree that it changed? */
  529.             drives[d] = 0;
  530.             changedrv(d);    /* yes -- do the change */
  531.             return 1;
  532.         }
  533.     }
  534.     return 0;
  535. }
  536.  
  537. /*
  538.  * routines for parsing path names
  539.  */
  540.  
  541. #define DIRSEP(p) ((p) == '\\')
  542.  
  543. /*
  544.  * relpath2cookie converts a TOS file name into a file cookie representing
  545.  * the directory the file resides in, and a character string representing
  546.  * the name of the file in that directory. The character string is
  547.  * copied into the "lastname" array. If lastname is NULL, then the cookie
  548.  * returned actually represents the file, instead of just the directory
  549.  * the file is in.
  550.  *
  551.  * note that lastname, if non-null, should be big enough to contain all the
  552.  * characters in "path", since if the file system doesn't want the kernel
  553.  * to do path name parsing we may end up just copying path to lastname
  554.  * and returning the current or root directory, as appropriate
  555.  *
  556.  * "relto" is the directory relative to which the search should start.
  557.  * if you just want the current directory, use path2cookie instead.
  558.  *
  559.  */
  560.  
  561. #define MAX_LINKS 4
  562.  
  563. long
  564. relpath2cookie(relto, path, lastname, res, depth)
  565.     fcookie *relto;
  566.     const char *path;
  567.     char *lastname;
  568.     fcookie *res;
  569.     int depth;
  570. {
  571.     fcookie dir;
  572.     int drv;
  573.     int len;
  574.     char c, *s;
  575.     XATTR xattr;
  576.     static char newpath[16] = "U:\\DEV\\";
  577.     char temp2[PATH_MAX];
  578.     char linkstuff[PATH_MAX];
  579.     long r;
  580.  
  581. /* dolast: 0 == return a cookie for the directory the file is in
  582.  *         1 == return a cookie for the file itself, don't follow links
  583.  *       2 == return a cookie for whatever the file points at
  584.  */
  585.     int dolast = 0;
  586.     int i = 0;
  587.  
  588.     if (!lastname) {
  589.         dolast = 1;
  590.         lastname = temp2;
  591.     } else if (lastname == follow_links) {
  592.         dolast = 2;
  593.         lastname = temp2;
  594.     }
  595.  
  596.     *lastname = 0;
  597.  
  598. PATH2COOKIE_DB(("relpath2cookie(%s, dolast=%d, depth=%d)", path, dolast, depth));
  599.  
  600.     if (depth > MAX_LINKS) {
  601.         DEBUG(("Too many symbolic links"));
  602.         return ELOOP;
  603.     }
  604. /* special cases: CON:, AUX:, etc. should be converted to U:\DEV\CON,
  605.  * U:\DEV\AUX, etc.
  606.  */
  607.     if (strlen(path) == 4 && path[3] == ':') {
  608.         strncpy(newpath+7, path, 3);
  609.         path = newpath;
  610.     }
  611.  
  612. /* first, check for a drive letter */
  613. /* BUG: a '\' at the start of a symbolic link is relative to the current
  614.  * drive of the process, not the drive the link is located on
  615.  */
  616.     if (path[1] == ':') {
  617.         c = path[0];
  618.         if (c >= 'a' && c <= 'z')
  619.             drv = c - 'a';
  620.         else if (c >= 'A' && c <= 'Z')
  621.             drv = c - 'A';
  622.         else
  623.             goto nodrive;
  624.         path += 2;
  625.         i = 1;        /* remember that we saw a drive letter */
  626.     } else {
  627. nodrive:
  628.         drv = curproc->curdrv;
  629.     }
  630.  
  631. /* see if the path is rooted from '\\' */
  632.     if (DIRSEP(*path)) {
  633.         while(DIRSEP(*path))path++;
  634.         dup_cookie(&dir, &curproc->root[drv]);
  635.     } else {
  636.         if (i)    {    /* an explicit drive letter was given */
  637.             dup_cookie(&dir, &curproc->curdir[drv]);
  638.         }
  639.         else
  640.             dup_cookie(&dir, relto);
  641.     }
  642.  
  643.     if (!dir.fs) {
  644.         changedrv(dir.dev);
  645.         dup_cookie(&dir, &curproc->root[drv]);
  646.     }
  647.  
  648.     if (!dir.fs) {
  649.         DEBUG(("path2cookie: no file system: returning EDRIVE"));
  650.         return EDRIVE;
  651.     }
  652.  
  653.     /* here's where we come when we've gone across a mount point */
  654.     
  655. restart_mount:
  656.  
  657.     if (!*path) {        /* nothing more to do */
  658. PATH2COOKIE_DB(("relpath2cookie: no more path, returning 0"));
  659.         *res = dir;
  660.         return 0;
  661.     }
  662.  
  663. /* see if there has been a disk change; if so, return E_CHNG.
  664.  * path2cookie will restart the search automatically; other functions
  665.  * that call relpath2cookie directly will have to fail gracefully
  666.  */
  667.     if ((r = disk_changed(dir.dev)) != 0) {
  668.         release_cookie(&dir);
  669.         if (r > 0) r = E_CHNG;
  670. PATH2COOKIE_DB(("relpath2cookie: returning %d", r));
  671.         return r;
  672.     }
  673.  
  674.  
  675.     if (dir.fs->fsflags & FS_KNOPARSE) {
  676.         if (!dolast) {
  677. PATH2COOKIE_DB(("fs is a KNOPARSE, nothing to do"));
  678.             strncpy(lastname, path, PATH_MAX-1);
  679.             lastname[PATH_MAX - 1] = 0;
  680.             r = 0;
  681.             *res = dir;
  682.         } else {
  683. PATH2COOKIE_DB(("fs is a KNOPARSE, calling lookup"));
  684.             r = (*dir.fs->lookup)(&dir, path, res);
  685.             if (r == EMOUNT) {    /* hmmm... a ".." at a mount point, maybe */
  686.                 fcookie mounteddir;
  687.                 r = (*dir.fs->root)(dir.dev, &mounteddir);
  688.                 if (r == 0 && drv == UNIDRV) {
  689.                     if (dir.fs == mounteddir.fs &&
  690.                         dir.index == mounteddir.index &&
  691.                         dir.dev == mounteddir.dev) {
  692.                         release_cookie(&dir);
  693.                         release_cookie(&mounteddir);
  694.                         dup_cookie(&dir, &curproc->root[UNIDRV]);
  695.                         TRACE(("path2cookie: restarting from mount point"));
  696.                         goto restart_mount;
  697.                     }
  698.                 } else {
  699.                     if (r == 0)
  700.                         release_cookie(&mounteddir);
  701.                     r = 0;
  702.                 }
  703.             }
  704.             release_cookie(&dir);
  705.         }
  706.         PATH2COOKIE_DB(("relpath2cookie: returning %ld", r));
  707.         return r;
  708.     }
  709.  
  710.  
  711. /* parse all but (possibly) the last component of the path name */
  712. /* rules here: at the top of the loop, &dir is the cookie of
  713.  * the directory we're in now, xattr is its attributes, and res is unset
  714.  * at the end of the loop, &dir is unset, and either r is nonzero
  715.  * (to indicate an error) or res is set to the final result
  716.  */
  717.     r = (dir.fs->getxattr)(&dir, &xattr);
  718.     if (r) {
  719.         DEBUG(("couldn't get directory attributes"));
  720.         release_cookie(&dir);
  721.         return EINTRN;
  722.     }
  723.  
  724.     while (*path) {
  725.  
  726.     /* now we must have a directory, since there are more things in the path */
  727.         if ((xattr.mode & S_IFMT) != S_IFDIR) {
  728. PATH2COOKIE_DB(("relpath2cookie: not a directory, returning EPTHNF"));
  729.             release_cookie(&dir);
  730.             r = EPTHNF;
  731.             break;
  732.         }
  733.     /* we must also have search permission for the directory */
  734.         if (denyaccess(&xattr, S_IXOTH)) {
  735.             DEBUG(("search permission in directory denied"));
  736.             release_cookie(&dir);
  737.             r = EPTHNF;
  738.             break;
  739.         }
  740.  
  741.     /* if there's nothing left in the path, we can break here */
  742.         if (!*path) {
  743. PATH2COOKIE_DB(("relpath2cookie: no more path, breaking (1)"));
  744.             *res = dir;
  745.             break;
  746.         }
  747.     /* next, peel off the next name in the path */
  748.         len = 0;
  749.         s = lastname;
  750.         c = *path;
  751.         while (c && !DIRSEP(c)) {
  752.             if (len++ < PATH_MAX)
  753.                 *s++ = c;
  754.             c = *++path;
  755.         }
  756.         *s = 0;
  757.  
  758.     /* if there are no more names in the path, and we don't want
  759.      * to actually look up the last name, then we're done
  760.      */
  761.         if (dolast == 0 && !*path) {
  762.             *res = dir;
  763. PATH2COOKIE_DB(("relpath2cookie: no more path, breaking (2)"));
  764.             break;
  765.         }
  766.  
  767.  
  768.     /* 
  769.      * skip trailing slashes
  770.      */
  771.         while (DIRSEP(*path)) path++;
  772.  
  773. PATH2COOKIE_DB(("relpath2cookie: looking up [%s]", lastname));
  774.  
  775.         r = (*dir.fs->lookup)(&dir, lastname, res);
  776.         if (r == EMOUNT) {
  777.             fcookie mounteddir;
  778.             r = (*dir.fs->root)(dir.dev, &mounteddir);
  779.             if (r == 0 && drv == UNIDRV) {
  780.                 if (samefile(&dir, &mounteddir)) {
  781.                     release_cookie(&dir);
  782.                     release_cookie(&mounteddir);
  783.                     dup_cookie(&dir, &curproc->root[UNIDRV]);
  784.                     TRACE(("path2cookie: restarting from mount point"));
  785.                     goto restart_mount;
  786.                 } else if (r == 0) {
  787.                     r = EINTRN;
  788.                     release_cookie(&mounteddir);
  789.                     release_cookie(&dir);
  790.                     break;
  791.                 }
  792.             } else if (r == 0) {
  793.                 release_cookie(&mounteddir);
  794.             } else {
  795.                 release_cookie(&dir);
  796.                 break;
  797.             }
  798.         } else if (r) {
  799.             release_cookie(&dir);
  800.             break;
  801.         }
  802.  
  803.     /* check for a symbolic link */
  804.         r = (res->fs->getxattr)(res, &xattr);
  805.         if (r != 0) {
  806.             DEBUG(("path2cookie: couldn't get file attributes"));
  807.             release_cookie(&dir);
  808.             release_cookie(res);
  809.             break;
  810.         }
  811.  
  812.     /* if the file is a link, and we're following links, follow it */
  813.         if ( (xattr.mode & S_IFMT) == S_IFLNK && (*path || dolast > 1)) {
  814.             r = (res->fs->readlink)(res, linkstuff, PATH_MAX);
  815.             release_cookie(res);
  816.             if (r) {
  817.                 DEBUG(("error reading symbolic link"));
  818.                 release_cookie(&dir);
  819.                 break;
  820.             }
  821.             r = relpath2cookie(&dir, linkstuff, follow_links, res,
  822.                         depth+1);
  823.             release_cookie(&dir);
  824.             if (r) {
  825.                 DEBUG(("error following symbolic link"));
  826.                 break;
  827.             }
  828.             dir = *res;
  829.             (void)(res->fs->getxattr)(res, &xattr);
  830.         } else {
  831.             release_cookie(&dir);
  832.             dir = *res;
  833.         }
  834.     }
  835.  
  836.     PATH2COOKIE_DB(("relpath2cookie: returning %ld", r));
  837.     return r;
  838. }
  839.  
  840. #define MAX_TRYS 8
  841.  
  842. long
  843. path2cookie(path, lastname, res)
  844.     const char *path;
  845.     char *lastname;
  846.     fcookie *res;
  847. {
  848.     fcookie *dir;
  849.     long r;
  850. /* AHDI sometimes will keep insisting that a media change occured;
  851.  * we limit the number of retrys to avoid hanging the system
  852.  */
  853.     int trycnt = 0;
  854.  
  855.     dir = &curproc->curdir[curproc->curdrv];
  856.  
  857.     do {
  858.         r = relpath2cookie(dir, path, lastname, res, 0);
  859.         if (r == E_CHNG)
  860.             DEBUG(("path2cookie: restarting due to media change"));
  861.     } while (r == E_CHNG && trycnt++ < MAX_TRYS);
  862.  
  863.     return r;
  864. }
  865.  
  866. /*
  867.  * release_cookie: tell the file system owner that a cookie is no
  868.  * longer in use by the kernel
  869.  */
  870. void
  871. release_cookie(fc)
  872.     fcookie *fc;
  873. {
  874.     FILESYS *fs;
  875.  
  876.     if (fc) {
  877.         fs = fc->fs;
  878.         if (fs && fs->release) {
  879.             (void)(*fs->release)(fc);
  880.         }
  881.     }
  882. }
  883.  
  884. /*
  885.  * Make a new cookie (newc) which is a duplicate of the old cookie
  886.  * (oldc). This may be something the file system is interested in,
  887.  * so we give it a chance to do the duplication; if it doesn't
  888.  * want to, we just copy.
  889.  */
  890.  
  891. void
  892. dup_cookie(newc, oldc)
  893.     fcookie *newc, *oldc;
  894. {
  895.     FILESYS *fs = oldc->fs;
  896.  
  897.     if (fs && fs->release && fs->dupcookie) {
  898.         (void)(*fs->dupcookie)(newc, oldc);
  899.     } else {
  900.         *newc = *oldc;
  901.     }
  902. }
  903.  
  904. /*
  905.  * new_fileptr, dispose_fileptr: allocate (deallocate) a file pointer
  906.  */
  907.  
  908. FILEPTR *
  909. new_fileptr()
  910. {
  911.     FILEPTR *f;
  912.  
  913.     if ((f = flist) != 0) {
  914.         flist = f->next;
  915.         f->next = 0;
  916.         return f;
  917.     }
  918.     f = kmalloc(SIZEOF(FILEPTR));
  919.     if (!f) {
  920.         FATAL("new_fileptr: out of memory");
  921.     }
  922.     else {
  923.         f->next = 0;
  924.     }
  925.     return f;
  926. }
  927.  
  928. void
  929. dispose_fileptr(f)
  930.     FILEPTR *f;
  931. {
  932.     if (f->links != 0) {
  933.         FATAL("dispose_fileptr: f->links == %d", f->links);
  934.     }
  935.     f->next = flist;
  936.     flist = f;
  937. }
  938.  
  939. /*
  940.  * denyshare(list, f): "list" points at the first FILEPTR in a
  941.  * chained list of open FILEPTRS referring to the same file;
  942.  * f is a newly opened FILEPTR. Every FILEPTR in the given list is
  943.  * checked to see if its "open" mode (in list->flags) is compatible with
  944.  * the open mode in f->flags. If not (for example, if f was opened with
  945.  * a "read" mode and some other file has the O_DENYREAD share mode),
  946.  * then 1 is returned. If all the open FILEPTRs in the list are
  947.  * compatible with f, then 0 is returned.
  948.  * This is not as complicated as it sounds. In practice, just keep a
  949.  * list of open FILEPTRs attached to each file, and put something like
  950.  *     if (denyshare(thisfile->openfileptrlist, newfileptr))
  951.  *        return EACCDN;
  952.  * in the device open routine.
  953.  */
  954.  
  955. int ARGS_ON_STACK 
  956. denyshare(list, f)
  957.     FILEPTR *list, *f;
  958. {
  959.     int newrm, newsm;    /* new read and sharing mode */
  960.     int oldrm, oldsm;    /* read and sharing mode of already opened file */
  961.     int i;
  962.  
  963.     newrm = f->flags & O_RWMODE;
  964.     newsm = f->flags & O_SHMODE;
  965.  
  966. /*
  967.  * O_EXEC gets treated the same as O_RDONLY for our purposes
  968.  */
  969.     if (newrm == O_EXEC) newrm = O_RDONLY;
  970.  
  971. /* New meaning for O_COMPAT: deny write access to all _other_
  972.  * processes.
  973.  */
  974.  
  975.     for ( ; list; list = list->next) {
  976.         oldrm = list->flags & O_RWMODE;
  977.         if (oldrm == O_EXEC) oldrm = O_RDONLY;
  978.         oldsm = list->flags & O_SHMODE;
  979.         if (oldsm == O_DENYW || oldsm == O_DENYRW) {
  980.              if (newrm != O_RDONLY) {
  981.                 DEBUG(("write access denied"));
  982.                 return 1;
  983.             }
  984.         }
  985.         if (oldsm == O_DENYR || oldsm == O_DENYRW) {
  986.             if (newrm != O_WRONLY) {
  987.                 DEBUG(("read access denied"));
  988.                 return 1;
  989.             }
  990.         }
  991.         if (newsm == O_DENYW || newsm == O_DENYRW) {
  992.             if (oldrm != O_RDONLY) {
  993.                 DEBUG(("couldn't deny writes"));
  994.                 return 1;
  995.             }
  996.         }
  997.         if (newsm == O_DENYR || newsm == O_DENYRW) {
  998.             if (oldrm != O_WRONLY) {
  999.                 DEBUG(("couldn't deny reads"));
  1000.                 return 1;
  1001.             }
  1002.         }
  1003. /* If either sm == O_COMPAT, then we check to make sure
  1004.    that the file pointers are owned by the same process (O_COMPAT means
  1005.    "deny writes to any other processes"). This isn't quite the same
  1006.    as the Atari spec, which says O_COMPAT means "deny access to other
  1007.    processes." We should fix the spec.
  1008.  */
  1009.         if ((newsm == O_COMPAT && newrm != O_RDONLY && oldrm != O_RDONLY) ||
  1010.             (oldsm == O_COMPAT && newrm != O_RDONLY)) {
  1011.             for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  1012.                 if (curproc->handle[i] == list)
  1013.                     goto found;
  1014.             }
  1015.         /* old file pointer is not open by this process */
  1016.             DEBUG(("O_COMPAT file was opened for writing by another process"));
  1017.             return 1;
  1018.         found:
  1019.             ;    /* everything is OK */
  1020.         }
  1021.     }
  1022.     return 0;
  1023. }
  1024.  
  1025. /*
  1026.  * denyaccess(XATTR *xattr, unsigned perm): checks to see if the access
  1027.  * specified by perm (which must be some combination of S_IROTH, S_IWOTH,
  1028.  * and S_IXOTH) should be granted to the current process
  1029.  * on a file with the given extended attributes. Returns 0 if access
  1030.  * by the current process is OK, 1 if not.
  1031.  */
  1032.  
  1033. int
  1034. denyaccess(xattr, perm)
  1035.     XATTR *xattr;
  1036.     unsigned perm;
  1037. {
  1038.     unsigned mode;
  1039.  
  1040. /* the super-user can do anything! */
  1041.     if (curproc->euid == 0)
  1042.         return 0;
  1043.  
  1044.     mode = xattr->mode;
  1045.     if (curproc->euid == xattr->uid)
  1046.         perm = perm << 6;
  1047.     else if (curproc->egid == xattr->gid)
  1048.         perm = perm << 3;
  1049.     if ((mode & perm) != perm) return 1;    /* access denied */
  1050.     return 0;
  1051. }
  1052.  
  1053. /*
  1054.  * Checks a lock against a list of locks to see if there is a conflict.
  1055.  * This is a utility to be used by file systems, somewhat like denyshare
  1056.  * above. Returns 0 if there is no conflict, or a pointer to the
  1057.  * conflicting LOCK structure if there is.
  1058.  *
  1059.  * Conflicts occur for overlapping locks if the process id's are
  1060.  * different and if at least one of the locks is a write lock.
  1061.  *
  1062.  * NOTE: we assume before being called that the locks have been converted
  1063.  * so that l_start is absolute. not relative to the current position or
  1064.  * end of file.
  1065.  */
  1066.  
  1067. LOCK * ARGS_ON_STACK 
  1068. denylock(list, lck)
  1069.     LOCK *list, *lck;
  1070. {
  1071.     LOCK *t;
  1072.     unsigned long tstart, tend;
  1073.     unsigned long lstart, lend;
  1074.     int pid = curproc->pid;
  1075.     int ltype;
  1076.  
  1077.     ltype = lck->l.l_type;
  1078.     lstart = lck->l.l_start;
  1079.  
  1080.     if (lck->l.l_len == 0)
  1081.         lend = 0xffffffffL;
  1082.     else
  1083.         lend = lstart + lck->l.l_len - 1;
  1084.  
  1085.     for (t = list; t; t = t->next) {
  1086.         tstart = t->l.l_start;
  1087.         if (t->l.l_len == 0)
  1088.             tend = 0xffffffffL;
  1089.         else
  1090.             tend = tstart + t->l.l_len - 1;
  1091.  
  1092.     /* look for overlapping locks */
  1093.         if (tstart <= lstart && tend >= lstart && t->l.l_pid != pid &&
  1094.             (ltype == F_WRLCK || t->l.l_type == F_WRLCK))
  1095.             break;
  1096.         if (lstart <= tstart && lend >= tstart && t->l.l_pid != pid &&
  1097.             (ltype == F_WRLCK || t->l.l_type == F_WRLCK))
  1098.             break;
  1099.     }
  1100.     return t;
  1101. }
  1102.  
  1103. /*
  1104.  * check to see that a file is a directory, and that write permission
  1105.  * is granted; return an error code, or 0 if everything is ok.
  1106.  */
  1107. long
  1108. dir_access(dir, perm)
  1109.     fcookie *dir;
  1110.     unsigned perm;
  1111. {
  1112.     XATTR xattr;
  1113.     long r;
  1114.  
  1115.     r = (*dir->fs->getxattr)(dir, &xattr);
  1116.     if (r) {
  1117.         DEBUG(("dir_access: file system returned %ld", r));
  1118.         return r;
  1119.     }
  1120.     if ( (xattr.mode & S_IFMT) != S_IFDIR ) {
  1121.         DEBUG(("file is not a directory"));
  1122.         return EPTHNF;
  1123.     }
  1124.     if (denyaccess(&xattr, perm)) {
  1125.         DEBUG(("no permission for directory"));
  1126.         return EACCDN;
  1127.     }
  1128.     return 0;
  1129. }
  1130.  
  1131. /*
  1132.  * returns 1 if the given name contains a wildcard character 
  1133.  */
  1134.  
  1135. int
  1136. has_wild(name)
  1137.     const char *name;
  1138. {
  1139.     char c;
  1140.  
  1141.     while ((c = *name++) != 0) {
  1142.         if (c == '*' || c == '?') return 1;
  1143.     }
  1144.     return 0;
  1145. }
  1146.  
  1147. /*
  1148.  * void copy8_3(dest, src): convert a file name (src) into DOS 8.3 format
  1149.  * (in dest). Note the following things:
  1150.  * if a field has less than the required number of characters, it is
  1151.  * padded with blanks
  1152.  * a '*' means to pad the rest of the field with '?' characters
  1153.  * special things to watch for:
  1154.  *    "." and ".." are more or less left alone
  1155.  *    "*.*" is recognized as a special pattern, for which dest is set
  1156.  *    to just "*"
  1157.  * Long names are truncated. Any extensions after the first one are
  1158.  * ignored, i.e. foo.bar.c -> foo.bar, foo.c.bar->foo.c.
  1159.  */
  1160.  
  1161. void
  1162. copy8_3(dest, src)
  1163.     char *dest;
  1164.     const char *src;
  1165. {
  1166.     char fill = ' ', c;
  1167.     int i;
  1168.  
  1169.     if (src[0] == '.') {
  1170.         if (src[1] == 0) {
  1171.             strcpy(dest, ".       .   ");
  1172.             return;
  1173.         }
  1174.         if (src[1] == '.' && src[2] == 0) {
  1175.             strcpy(dest, "..      .   ");
  1176.             return;
  1177.         }
  1178.     }
  1179.     if (src[0] == '*' && src[1] == '.' && src[2] == '*' && src[3] == 0) {
  1180.         dest[0] = '*';
  1181.         dest[1] = 0;
  1182.         return;
  1183.     }
  1184.  
  1185.     for (i = 0; i < 8; i++) {
  1186.         c = *src++;
  1187.         if (!c || c == '.') break;
  1188.         if (c == '*') {
  1189.             fill = c = '?';
  1190.         }
  1191.         *dest++ = toupper(c);
  1192.     }
  1193.     while (i++ < 8) {
  1194.         *dest++ = fill;
  1195.     }
  1196.     *dest++ = '.';
  1197.     i = 0;
  1198.     fill = ' ';
  1199.     while (c && c != '.')
  1200.         c = *src++;
  1201.  
  1202.     if (c) {
  1203.         for( ;i < 3; i++) {
  1204.             c = *src++;
  1205.             if (!c || c == '.') break;
  1206.             if (c == '*')
  1207.                 c = fill = '?';
  1208.             *dest++ = toupper(c);
  1209.         }
  1210.     }
  1211.     while (i++ < 3)
  1212.         *dest++ = fill;
  1213.     *dest = 0;
  1214. }
  1215.  
  1216. /*
  1217.  * int pat_match(name, patrn): returns 1 if "name" matches the template in
  1218.  * "patrn", 0 if not. "patrn" is assumed to have been expanded in 8.3
  1219.  * format by copy8_3; "name" need not be. Any '?' characters in patrn
  1220.  * will match any character in name. Note that if "patrn" has a '*' as
  1221.  * the first character, it will always match; this will happen only if
  1222.  * the original pattern (before copy8_3 was applied) was "*.*".
  1223.  *
  1224.  * BUGS: acts a lot like the silly TOS pattern matcher.
  1225.  */
  1226.  
  1227. int
  1228. pat_match(name, template)
  1229.     const char *name, *template;
  1230. {
  1231.     register char *s, c;
  1232.     char expname[TOS_NAMELEN+1];
  1233.  
  1234.     if (*template == '*') return 1;
  1235.     copy8_3(expname, name);
  1236.  
  1237.     s = expname;
  1238.     while ((c = *template++) != 0) {
  1239.         if (c != *s && c != '?')
  1240.             return 0;
  1241.         s++;
  1242.     }
  1243.     return 1;
  1244. }
  1245.  
  1246. /*
  1247.  * int samefile(fcookie *a, fcookie *b): returns 1 if the two cookies
  1248.  * refer to the same file or directory, 0 otherwise
  1249.  */
  1250.  
  1251. int
  1252. samefile(a, b)
  1253.     fcookie *a, *b;
  1254. {
  1255.     if (a->fs == b->fs && a->dev == b->dev && a->index == b->index)
  1256.         return 1;
  1257.     return 0;
  1258. }
  1259.